package com.copa.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

/**
 * @author copa
 * @createDate 2021-09-23 9:05
 * @function 服务端
 */
public class Server {

    public void start() throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        Selector selector = Selector.open();
        // 绑定8080端口
        serverSocketChannel.bind(new InetSocketAddress(8080));
        // 通道必须为非阻塞，否则会报异常
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务器启动成功！");
        while (true) {
            // 如果没有连接
            if (selector.select() == 0) {
                continue;
            }
            Set<SelectionKey> selectionKeySet = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeySet.iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                if (selectionKey.isAcceptable()) {
                    // 如果是请求状态
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    // 通道必须为非阻塞，否则会报异常
                    socketChannel.configureBlocking(false);
                    // 注册可读选择器
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    // 发送公告
                    socketChannel.write(Charset.forName("UTF-8").encode("欢迎来到聊天室，请注意隐私安全~指令personNum为在线统计人数"));
                }
                if (selectionKey.isReadable()) {
                    // 如果是可读状态
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    if (!socketChannel.isConnected()) {
                        socketChannel.finishConnect();
                    }
                    int readLength = 0;

                    try {
                        // 检测用户是否下线和输入内容
                        readLength = socketChannel.read(buffer);
                    } catch (IOException e) {
                        // 该客户端下线
                        socketChannel.close();
                        System.out.println("有一用户下线~");
                        continue;
                    }

                    String message = "";
                    if (readLength > 0) {
                        // 若有内容，则作处理，转换buffer模式
                        buffer.flip();
                        message += Charset.forName("UTF-8").decode(buffer);
                    }
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    if (message.length() > 0) {
                        // 显示内容
                        System.out.println(message);
                        Set<SelectionKey> userSet = selector.keys();
                        if (message.contains(":personNum")) {
                            // TODO:这里没有对名字进行处理，只是判断包含这个就是查询在线人数
                            socketChannel.write(Charset.forName("UTF-8").encode("在线人数为：" + (userSet.toArray().length - 1)));
                            iterator.remove();
                            continue;
                        }

                        // 广播消息，相当于群聊
                        for (SelectionKey key : userSet) {
                            if (key.channel() instanceof SocketChannel && key.channel() != socketChannel) {
                                // 不用给自己发送消息
                                ((SocketChannel) key.channel()).write(Charset.forName("UTF-8").encode(message));
                            }
                        }
                    }
                }
                iterator.remove();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new Server().start();
    }
}
